This repository has no description
4.8 kB
168 lines
1'use client';
2
3import { useEffect, useState } from 'react';
4import { useRouter, useParams } from 'next/navigation';
5import { getAccessToken } from '@/services/auth';
6import { ApiClient } from '@/api-client/ApiClient';
7import { UrlCard } from '@/components/UrlCard';
8import type { GetCollectionPageResponse } from '@/api-client/types';
9import {
10 Button,
11 Group,
12 Loader,
13 Stack,
14 Text,
15 Card,
16 Title,
17 Box,
18 SimpleGrid,
19} from '@mantine/core';
20
21export default function CollectionPage() {
22 const [collection, setCollection] =
23 useState<GetCollectionPageResponse | null>(null);
24 const [loading, setLoading] = useState(true);
25 const [error, setError] = useState('');
26 const router = useRouter();
27 const params = useParams();
28 const collectionId = params.collectionId as string;
29
30 // Create API client instance
31 const apiClient = new ApiClient(
32 process.env.NEXT_PUBLIC_API_BASE_URL || 'http://localhost:3000',
33 () => getAccessToken(),
34 );
35
36 useEffect(() => {
37 const fetchCollection = async () => {
38 try {
39 setLoading(true);
40 const response = await apiClient.getCollectionPage(collectionId, {
41 limit: 50,
42 });
43 setCollection(response);
44 } catch (error: any) {
45 console.error('Error fetching collection:', error);
46 setError(error.message || 'Failed to load collection');
47 } finally {
48 setLoading(false);
49 }
50 };
51
52 if (collectionId) {
53 fetchCollection();
54 }
55 }, [collectionId]);
56
57 if (loading) {
58 return <Loader />;
59 }
60
61 if (error || !collection) {
62 return (
63 <Stack align="center">
64 <Text c={'red'}>{error || 'Collection not found'}</Text>
65 <Button onClick={() => router.back()}>Go Back</Button>
66 </Stack>
67 );
68 }
69
70 return (
71 <Box>
72 <Stack>
73 <Group justify="space-between">
74 <Button variant="outline" onClick={() => router.back()}>
75 ← Back
76 </Button>
77 <Group>
78 <Button
79 variant="outline"
80 onClick={() => router.push(`/collections/${collectionId}/edit`)}
81 >
82 Edit Collection
83 </Button>
84 <Button
85 onClick={() =>
86 router.push(`/cards/add?collectionId=${collectionId}`)
87 }
88 >
89 Add Card
90 </Button>
91 </Group>
92 </Group>
93
94 {/* Collection Header */}
95 <Card withBorder>
96 <Stack>
97 <Text fw={600} lineClamp={1}>
98 {collection.name}
99 </Text>
100 {collection.description && (
101 <Text lineClamp={2}>{collection.description}</Text>
102 )}
103 </Stack>
104
105 <Group>
106 <Text fz={'sm'} c={'gray'}>
107 {collection.urlCards.length} cards
108 </Text>
109 <Text fz={'sm'} c={'gray'}>
110 By {collection.author.name} (@{collection.author.handle})
111 </Text>
112 </Group>
113 </Card>
114
115 {/* Cards Section */}
116 <Stack>
117 <Group justify="space-between">
118 <Title order={2}>Cards</Title>
119 {collection.pagination && collection.pagination.totalCount > 0 && (
120 <Text fz={'sm'} c={'gray'}>
121 Showing {collection.urlCards.length} of{' '}
122 {collection.pagination.totalCount} cards
123 </Text>
124 )}
125 </Group>
126
127 {collection.urlCards.length > 0 ? (
128 <Box>
129 <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing={'md'}>
130 {collection.urlCards.map((card) => (
131 <UrlCard
132 key={card.id}
133 cardId={card.id}
134 url={card.url}
135 title={card.cardContent.title}
136 description={card.cardContent.description}
137 author={card.cardContent.author}
138 imageUrl={card.cardContent.thumbnailUrl}
139 addedAt={card.createdAt}
140 note={card.note?.text}
141 />
142 ))}
143 </SimpleGrid>
144
145 {/* Pagination */}
146 {collection.pagination && collection.pagination.hasMore && (
147 <Stack align="center">
148 <Button variant="outline">Load More Cards</Button>
149 </Stack>
150 )}
151 </Box>
152 ) : (
153 <Stack align="center">
154 <Text c={'gray'}>No cards in this collection yet</Text>
155 <Button
156 onClick={() =>
157 router.push(`/cards/add?collectionId=${collectionId}`)
158 }
159 >
160 Add Your First Card
161 </Button>
162 </Stack>
163 )}
164 </Stack>
165 </Stack>
166 </Box>
167 );
168}